#include "GA.h"
#include "LED.h"
#include "Button.h"
#include "h1010.h"

enum eGA_Events {
	GA_EV_ALARM = 0,
	GA_EV_TIMER = 1,
	GA_EV_BUTTON = 2,
	GA_EV_DRIVER = 3
};
enum eGA_TimerRequest {
	START_PRE_ALERT = 0,
	START_ALERT = 1,
	START_EVAC_INHIBIT = 2,
	START_EVAC_AUTO = 3,
	START_EVAC = 4,
	START_NORMAL = 5
};

struct GA_threadInfo_t {
	BYTE state;
	enum LED_INDEX alarmLed;
	enum LED_INDEX faultLed;
	enum LED_INDEX globalAlarmLed;
	enum eGA_newAlm newAlm;
	enum eGA_Status status;
	BYTE siMask;
	unsigned int oneSecTickCount;
	unsigned int oneSecTickCountAlarm;
	unsigned int oneSecTickCountAutoSilence;
	unsigned int autoSilenceTimerAdjusted;
	BYTE isAcked;
	BYTE skipEvac;
	struct GA * pGA;
};
typedef void(*pGaFxnRtnVoidParamBYTE)(unsigned char);
typedef void(*pGaStateFxn) (void);

struct GA_stateInfo_t {
	enum eGA_States me;
	pGaStateFxn pStateFxnDuring;
	enum eGA_OutputStatus outputStatus;
};
static BYTE GA_updateAlmCount(void);
static void GA_stateDuring_GA_NORMAL(void);
static void GA_stateDuring_GA_PRE_ALERT(void);
static void GA_stateDuring_GA_ALERT(void);
static void GA_stateDuring_GA_EVAC_INHIBIT_SILENCE(void);
static void GA_stateDuring_GA_EVAC_AUTO_SILENCE(void);
static void GA_stateDuring_GA_EVAC(void);
static void GA_stateEnter_EVAC(void);
static void GA_changeState(enum eGA_States newState);
static void GA_stateDuring(void);
static void GA_stateMachine(void);
static enum eGA_Status GA_checkForValidAlertTimers(void);

static BYTE 						GA_SImask 			= 0;
static BYTE 						GA_SImaskLast		= 0;
static BYTE						GA_skipToEvacMask   = 0;
static BYTE						GA_skipToEvacMaskLast   = 0;
//enum eGA_Status 			GA_rawStatus 		= GA_inActive;
static enum eGA_Status 			GA_forcedOn 		= GA_inActive;
static enum eGA_OutputStatus 		GA_outputStatus 	= GA_STATUS_OFF;
static enum eGA_newAlm 			GA_newAlm 			= NOT_NEW;
static BYTE 						GA_almCount			= 0;
static enum eGA_cfgSilenceInAlert 	GA_silenceInAlert 	= silenceInAlertDisabled;
static enum eGA_silence			GA_isSilenced 		= NOT_SILENCED;
static enum eGA_States 			GA_state 			= GA_NORMAL;
static enum eGA_skipToEvac 		GA_skipToEvac 		= DO_NOT_SKIP_EVAC;
//static int							GA_timer 			= 0;
//static int							GA_alertTimer 		= 0;
static enum eGA_AlertOnOff 		GA_alertOnOff		= GA_ALERT_ON;
static enum eGA_Status 			GA_alertOnOffenabled = GA_Active;

static struct GA_threadInfo_t gaThreadInfo;
static struct GA * pGAconfig = 0;

static struct GA_stateInfo_t GA_stateTable [GA_StateCount] = {
		{GA_NORMAL, 				GA_stateDuring_GA_NORMAL, 				GA_STATUS_OFF},
		{GA_PRE_ALERT, 				GA_stateDuring_GA_PRE_ALERT, 			GA_STATUS_OFF},
		{GA_ALERT, 					GA_stateDuring_GA_ALERT, 				GA_STATUS_ON},
		{GA_EVAC_INHIBIT_SILENCE, 	GA_stateDuring_GA_EVAC_INHIBIT_SILENCE, GA_STATUS_ON},
		{GA_EVAC_AUTO_SILENCE, 		GA_stateDuring_GA_EVAC_AUTO_SILENCE, 	GA_STATUS_ON},
		{GA_EVAC, 					GA_stateDuring_GA_EVAC, 				GA_STATUS_ON}
};
/*
 * struct GA
    {
     BYTE Start;
     unsigned char GAEnableSilence : 1;
     unsigned char Unused : 7 ;
     BYTE PreAlertTimer;
     BYTE AlertTimer;
     BYTE EvacMinTimer;
     BYTE AutoSilenceTimer;
     BYTE GAAlertOnTimer;
     BYTE GAAlertOffTimer;
     BYTE End;
    } ;
 */

void GA_init(void)
{
	gaThreadInfo.pGA = (struct GA *)&pConfigMemRAM->ga;
	pGAconfig = gaThreadInfo.pGA;
	gaThreadInfo.oneSecTickCount = 0;
	gaThreadInfo.oneSecTickCountAlarm = 0;
	gaThreadInfo.oneSecTickCountAutoSilence = 0;
	gaThreadInfo.autoSilenceTimerAdjusted = gaThreadInfo.pGA->AutoSilenceTimer*10;

	GA_SImask = 0;
	GA_SImaskLast = 0;
	GA_skipToEvacMask   = 0;
	GA_skipToEvacMaskLast   = 0;
//	GA_rawStatus = GA_inActive;
	GA_outputStatus = GA_STATUS_OFF;
	GA_newAlm = NOT_NEW;
	GA_almCount = 0;
	GA_state = GA_NORMAL;
	GA_skipToEvac = DO_NOT_SKIP_EVAC;
	GA_forcedOn = GA_inActive;
//	GA_timer = 0;
	GA_alertOnOff = GA_ALERT_ON;
	GA_alertOnOffenabled = GA_checkForValidAlertTimers();
	GA_isSilenced = NOT_SILENCED;

	GA_silenceInAlert = silenceInAlertDisabled;
	if (pGAconfig->GAEnableSilence&silenceInAlertEnabled == silenceInAlertEnabled) {
		GA_silenceInAlert = silenceInAlertEnabled;
	}

}
void GA_notifyGA_SIalm(unsigned char inputMask, enum eGA_skipToEvac evac)
{
	GA_SImask |= inputMask;
	if (evac)
	{
		GA_skipToEvacMask |= inputMask;
	}
}
void GA_clearGA_SIalm(unsigned char inputMask)
{
	GA_SImask &= ~inputMask;
	GA_skipToEvacMask &= ~inputMask; // no harm to always do this, if it wasn't set, doesn't matter
}
BYTE GA_getGA_SIalm(void)
{
	return GA_SImask;
}
enum eGA_silence GA_getIsSilenced(void)
{
	return GA_isSilenced;
}
enum eGA_States GA_getState(void)
{
	return GA_state;
}
enum eGA_OutputStatus GA_statusForSOSZ(void)
{
	return GA_outputStatus;
}
enum eGA_AlertOnOff GA_getAlertOnOff(void)
{
	return GA_alertOnOff;
}
static enum eGA_Status GA_checkForValidAlertTimers(void)
{
	enum eGA_Status rtn = GA_Active;
	if ((pGAconfig->AlertTimer == 0) || (pGAconfig->GAAlertOnTimer == 0) || (pGAconfig->GAAlertOffTimer == 0))
	{
		rtn = GA_inActive;
	}
	return rtn;
}
static void GA_buttonHelper(enum eGA_Status isForcedOn, enum eGA_silence isSilenced, enum eGA_OutputStatus outputStatus, enum RATES rate)
{
	GA_forcedOn = isForcedOn;
	GA_isSilenced = isSilenced;
	GA_outputStatus = outputStatus;
	LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, rate);
}
static void GA_checkForGAbuttonsSM(void)
{
	if (evt_yes == BTN_btnEvent_get(eBtnGAon))
	{
		BTN_btnEvent_consume(eBtnGAoff);
		GA_buttonHelper(GA_Active, NOT_SILENCED, GA_STATUS_ON, RATE_OFF);
	}
	if (evt_yes == BTN_btnEvent_get(eBtnGAoff))
	{
		BTN_btnEvent_consume(eBtnGAoff);
		switch (GA_state)
		{
			case GA_NORMAL:
				GA_buttonHelper(GA_inActive, NOT_SILENCED, GA_STATUS_OFF, RATE_OFF);
				break;
			case GA_PRE_ALERT:
				// no effect here!
				break;
			case GA_ALERT:
				if (GA_silenceInAlert == silenceInAlertEnabled) // for Alert State
				{
					GA_alertOnOffenabled = GA_inActive;
					GA_alertOnOff = GA_ALERT_OFF;
					GA_buttonHelper(GA_inActive, SILENCED, GA_STATUS_OFF, RATE_ON);
				}
/*				else // (GA_silenceInAlert == silenceInAlertEnabled)
				{
					GA_buttonHelper(GA_inActive, NOT_SILENCED, GA_STATUS_OFF, RATE_OFF);
				}*/
				break;
			case GA_EVAC_INHIBIT_SILENCE:
				// no effect here!
				break;
			case GA_EVAC_AUTO_SILENCE:
			case GA_EVAC:
				if (GA_SImask)
				{
					GA_buttonHelper(GA_inActive, SILENCED, GA_STATUS_OFF, RATE_ON);
				}
				else
				{
					GA_buttonHelper(GA_inActive, NOT_SILENCED, GA_STATUS_OFF, RATE_OFF);
					GA_changeState(GA_NORMAL);
				}
				break;
		}
	}

}
/*static void GA_checkForGAbuttons(void)
{
	if (GA_silenceInAlert == silenceInAlertDisabled) // for Alert State
	{
		switch (GA_isSilenced)
		{
			case SILENCED:
				LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_ON);
				if (evt_yes == BTN_btnEvent_get(eBtnGAon))
				{
					BTN_btnEvent_consume(eBtnGAoff);
					GA_isSilenced = NOT_SILENCED;
					LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
				}
				break;
			case NOT_SILENCED:
				LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
				if (evt_yes == BTN_btnEvent_get(eBtnGAoff))
				{
					BTN_btnEvent_consume(eBtnGAoff);
					GA_isSilenced = SILENCED;
					LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_ON);
				}
				break;
		}
	}
	else // (GA_silenceInAlert == silenceInAlertEnabled)
	{
		LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
	}
}*/
static void GA_stateExit_GA_NORMAL(void)
{
	gaThreadInfo.oneSecTickCount = 0;
	if (pGAconfig->PreAlertTimer)
	{
		GA_changeState(GA_PRE_ALERT);
	}
	else if (pGAconfig->AlertTimer)
	{
		gaThreadInfo.oneSecTickCountAlarm = 0;
		gaThreadInfo.oneSecTickCountAutoSilence = 0;
		GA_alertOnOffenabled = GA_checkForValidAlertTimers();
		GA_alertOnOff = GA_ALERT_ON;
		GA_changeState(GA_ALERT);
	}
	else
	{
		GA_stateEnter_EVAC();
//		GA_changeState(GA_EVAC_INHIBIT_SILENCE);
	}
}
static void GA_stateDuring_GA_NORMAL(void)
{
	LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
	GA_isSilenced = NOT_SILENCED;
	// Test if GA is active
	if (GA_SImask)
	{
		GA_stateExit_GA_NORMAL();
	}
}
static void GA_stateDuring_GA_PRE_ALERT(void)
{
	LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
	GA_isSilenced = NOT_SILENCED;
/*	if (GA_SImask == 0)
	{
		GA_changeState(GA_NORMAL);
		return;
	}*/
	if (gaThreadInfo.oneSecTickCount++ == pGAconfig->PreAlertTimer)
	{
		gaThreadInfo.oneSecTickCount = 0;
		gaThreadInfo.oneSecTickCountAlarm = 0;
		gaThreadInfo.oneSecTickCountAutoSilence = 0;
		if (pGAconfig->AlertTimer)
		{
			GA_alertOnOffenabled = GA_checkForValidAlertTimers();
			GA_alertOnOff = GA_ALERT_ON;
			GA_changeState(GA_ALERT);
		}
		else
		{
			GA_stateEnter_EVAC();
//			GA_changeState(GA_EVAC_INHIBIT_SILENCE);
		}
	}
}
static void GA_alertOnOffCycling(void)
{
	switch (GA_alertOnOff)
	{
		case GA_ALERT_ON:
			if (gaThreadInfo.oneSecTickCountAlarm == (pGAconfig->GAAlertOnTimer>>1))
			{
				gaThreadInfo.oneSecTickCountAlarm = 0;
				GA_alertOnOff = GA_ALERT_OFF;
			}
			break;
		case GA_ALERT_OFF:
			if (gaThreadInfo.oneSecTickCountAlarm == (pGAconfig->GAAlertOffTimer>>1))
			{
				gaThreadInfo.oneSecTickCountAlarm = 0;
				GA_alertOnOff = GA_ALERT_ON;
			}
			break;
	}
	gaThreadInfo.oneSecTickCountAlarm++;
}
static void GA_stateDuring_GA_ALERT(void)
{
/*	if (GA_SImask == 0)
	{
		GA_changeState(GA_NORMAL);
		return;
	}*/
	if (gaThreadInfo.oneSecTickCount == pGAconfig->AlertTimer)
	{
		if (GA_SImask == 0)
		{
//			GA_changeState(GA_NORMAL);
			GA_alertOnOffenabled = GA_inActive;
			GA_alertOnOff = GA_ALERT_ON;
			GA_stateEnter_EVAC();
		}
		else
		{
			gaThreadInfo.oneSecTickCount = 0;
			gaThreadInfo.oneSecTickCountAlarm = 0;
			gaThreadInfo.oneSecTickCountAutoSilence = 0;
			GA_alertOnOffenabled = GA_inActive;
			GA_alertOnOff = GA_ALERT_ON;
	//		GA_changeState(GA_EVAC_INHIBIT_SILENCE);
			GA_stateEnter_EVAC();
		}
		return;
	}
	if (GA_alertOnOffenabled == GA_Active)
	{
		GA_alertOnOffCycling();
	}
	gaThreadInfo.oneSecTickCount++;
}
static void GA_stateEnter_EVAC(void)
{
	gaThreadInfo.oneSecTickCount = 0;
	GA_forcedOn = GA_Active;
	if (pGAconfig->EvacMinTimer)
	{
		GA_isSilenced = NOT_SILENCED;
		GA_changeState(GA_EVAC_INHIBIT_SILENCE);
	}
	else if (pGAconfig->AutoSilenceTimer)
	{
		GA_isSilenced = NOT_SILENCED;
		GA_changeState(GA_EVAC_AUTO_SILENCE);
	}
	else
	{
		if (GA_isSilenced != SILENCED)
		{
			GA_forcedOn = GA_Active; // Tag Think: Does this make sense to do always?
			GA_isSilenced = NOT_SILENCED;
		}
		else
		{
			GA_forcedOn = GA_inActive;
		}
		GA_changeState(GA_EVAC);
	}
}
static void GA_stateDuring_GA_EVAC_INHIBIT_SILENCE(void)
{
	if (gaThreadInfo.oneSecTickCount++ >= pGAconfig->EvacMinTimer)
	{
		if (pGAconfig->AutoSilenceTimer) {
			gaThreadInfo.oneSecTickCount = 0; // Tag To-do: reset timer function
			GA_changeState(GA_EVAC_AUTO_SILENCE);
		}
		else
		{
			gaThreadInfo.oneSecTickCount = 0; // Tag To-do: reset timer function
			GA_changeState(GA_EVAC);
		}
	}
/*	if (gaThreadInfo.oneSecTickCountAutoSilence++ == pGAconfig->AutoSilenceTimer)
	{
		gaThreadInfo.oneSecTickCountAutoSilence = 0;
		GA_changeState(GA_EVAC);
	}*/
}
static void GA_stateDuring_GA_EVAC_AUTO_SILENCE(void)
{
	if (gaThreadInfo.oneSecTickCount++ >= gaThreadInfo.autoSilenceTimerAdjusted)//pGAconfig->AutoSilenceTimer)
	{
		gaThreadInfo.oneSecTickCount = 0;
		GA_isSilenced = SILENCED;
		GA_forcedOn = GA_inActive;
		GA_changeState(GA_EVAC);
	}
}
static void GA_stateDuring_GA_EVAC(void)
{
	// you remain here till you get GA_OFF
	if (GA_SImask == 0)
	{
		if (GA_isSilenced == SILENCED)
		{
			GA_changeState(GA_NORMAL);
		}
		return;
	}
}
static void GA_changeState(enum eGA_States newState)
{
	GA_state = newState;
	GA_stateDuring();
}
static void GA_stateDuring(void)
{
	/* Note: There is a recursion issue that needs addressed. Because you can change state during this function and the change_state function calls GA_stateDuring
	 * So far this has not been an issue but it could be. */

	/* This is a high priority state change and applies to all states*/
	if (((GA_newAlm == NEW_ALM)&&(GA_almCount > 1)) || (GA_skipToEvac == SKIP_EVAC))//&&(GA_state != GA_EVAC_INHIBIT_SILENCE))//GA_NORMAL))
	{
		GA_isSilenced = NOT_SILENCED;
//		GA_forcedOn = GA_inActive;				// if someone had pressed the GA_ON button it is reasonable to assume that it should stay on until GA_OFF is pressed
		GA_newAlm = NOT_NEW;					// it is logically ok to clear newAlm and skipToEvac because, even if both are set, they go to the
		GA_skipToEvac = DO_NOT_SKIP_EVAC; 		// place and this is the only
		GA_stateEnter_EVAC();
	}

	/* Call the current state function.*/
	GA_stateTable[GA_state].pStateFxnDuring(); // Tag Think: There could be a state change here, recursively calling GA_stateDuring
	/* Drive the normal GA logical output for this state. The subsequent code could override the normal GA output. The physical output is controlled by the SO. */
	GA_outputStatus = GA_stateTable[GA_state].outputStatus;
	/* */
	if ((GA_state == GA_ALERT) && (GA_alertOnOff == GA_ALERT_OFF))
	{
		GA_outputStatus = GA_STATUS_OFF;
	}
	/* Check the GA ON and GA OFF button state*/
	GA_checkForGAbuttonsSM();
	/* Outputs from GA buttons -- these remain latched until another button press or another alarm or autosilence*/
	/* GA_forcedOn and GA_isSilenced are mutually exclusive*/
	if ((GA_forcedOn == GA_Active)&&(GA_isSilenced == SILENCED))
	{
		__no_operation();
//		Exception_handler("GA", GA_state, GA_fault_1);
	}
	else if (GA_forcedOn == GA_Active)
	{
		GA_outputStatus = GA_STATUS_ON;
		LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
	}
	else if (GA_isSilenced == SILENCED) // The led is only on if it is silenced
	{
		GA_outputStatus = GA_STATUS_OFF;
		LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_ON);
	}
	else
	{
//		GA_outputStatus = GA_STATUS_OFF;  // then output controlled by the state machine (normal behavior)
		LED_resourceArray_requestRate(LED_GLOBAL_GA_SILENCE, LED_GA_SILENCE, RATE_OFF);
	}
}
static void GA_stateMachine(void)
{
	switch (GA_state)
	{
		case GA_NORMAL:
		{
			GA_stateDuring();
		}
			break;
		case GA_PRE_ALERT:
		{
			GA_stateDuring();
		}
			break;
		case GA_ALERT:
		{
			GA_stateDuring();
		}
			break;
		case GA_EVAC_INHIBIT_SILENCE:
		{
			GA_stateDuring();
		}
			break;
		case GA_EVAC_AUTO_SILENCE:
		{
			GA_stateDuring();
		}
			break;
		case GA_EVAC:
		{
			GA_stateDuring();
		}
			break;
	}
}
static BYTE GA_updateAlmCount(void)
{
	BYTE count = 0;
	GA_newAlm = NOT_NEW;
	BYTE i;
	for (i=0; i<8; i++)
	{
		if (GA_SImask&(1<<i))
		{
			count++;
			if ((GA_SImaskLast&(1<<i))==0)
			{
				__no_operation();
				GA_newAlm = NEW_ALM;
			}
		}
		if (GA_skipToEvacMask&(1<<i))
		{
			__no_operation();
			if ((GA_skipToEvacMaskLast&(1<<i))==0)
			{
				GA_skipToEvac = SKIP_EVAC;
			}
		}
	}
//	if (GA_almCount > lastCount) {
//		GA_newAlm = NEW_ALM;
//	}
	GA_SImaskLast = GA_SImask;
	GA_almCount = count;
	GA_skipToEvacMaskLast = GA_skipToEvacMask;
	return count;
}
void GA_thread(void)
{
	/* GA Timers */


	/* This first round ignores the GA timers, it ignores the skip to evac request from SI.
	 * It ignores GA Silence Inhibit Stage.
	 *
	 * It has no access to SI or SOSZ.
	 * It can access push buttons.
	 * It can access timers.
	 * It can access led's.
	 * It can access mailbox, queue, shared memory -- between SI/GA and GA/SOSZ
	 */
	GA_updateAlmCount();
	GA_stateMachine();

	GA_newAlm = NOT_NEW;
	GA_skipToEvac = DO_NOT_SKIP_EVAC;

	// clear unused button presses
	BTN_btnEvent_clearGAbtns();
}

#if 0
/*****************************************************************************
*                               Securiplex Inc.                              *
*                                                                            *
******************************************************************************
*                                                                            *
*                                                                            *
*                        #####  ####### ######  #######                      *
*                       #     # #     # #     # #                            *
*                       #       #     # #     # #                            *
*                       #       #     # #     # #####                        *
*                       #       #     # #     # #                            *
*                       #     # #     # #     # #                            *
*                        #####  ####### ######  #######                      *
*                                                                            *
*                                                                            *
*               #     # ####### ######  #     # #       #######              *
*               ##   ## #     # #     # #     # #       #                    *
*               # # # # #     # #     # #     # #       #                    *
*               #  #  # #     # #     # #     # #       #####                *
*               #     # #     # #     # #     # #       #                    *
*               #     # #     # #     # #     # #       #                    *
*               #     # ####### ######   #####  ####### #######              *
*                                                                            *
*                                                                            *
******************************************************************************
*
*            Title: PROPAK CODE General Alarm Module
*      Part Number: sc-03668-09
*        $Revision: 1.1 $
*            $Date: 2003/02/06 09:34:59 $
*          $Source: /spx1/sw/TRE-16577-00/MEM-16245-00/src/mod_03668/sc_03668.c,v $
*
******************************************************************************
*                                                                            *
*                             PROPRIETARY LEGEND                             *
*                                                                            *
*            (C) Copyright Securiplex Inc, 2003, All Rights Reserved.        *
*                                                                            *
*      The information contained herein or herewith is the  confidential     *
*      and proprietary property of Securiplex Inc. The information shall     *
*      not, in whole or in part, be  reproduced,  copied,  disclosed  or     *
*      used  other than as expressly authorized by written permission of     *
*      Securiplex Inc.  The copyright and the foregoing  restriction  on     *
*      reproduction, copy, disclosure and use extend to all the media in     *
*      which this information may be  embodied,  including  magnetic  or     *
*      electronic  storage,  punch card, paper tape, computer print-out,     *
*      visual display, etc.                                                  *
*                                                                            *
******************************************************************************

******************************************************************************
*                   R E V I S I O N      H I S T O R Y                       *
******************************************************************************
* $Log:	sc_03668.c,v $
 * Revision 1.1  2003/02/06  09:34:59  09:34:59  patrickt (Patrick Therien)
 * Initial revision
 *
******************************************************************************

******************************************************************************
*                      I N C L U D E       F I L E S
*****************************************************************************/

/*#include "si_glb.h"    global
#include "si_03661.h"  mailboxes
#include "si_03677.h"  utilities
#include "si_03670.h"  linked tables
#include "si_03665.h"  gen pb if
#include "si_03672.h"  timer module
#include "si_03685.h"  input app
#include "si_03689.h"  master leds
#include "si_03667.h"  display
#include "si_03673.h"  ddb_mgr
#include "si_03668.h"  G.A.          */


/*****************************************************************************
*                            C O N S T A N T S
*****************************************************************************/

/* state machine values */
#define GA_NORMAL        0
#define PRE_GA_ALERT     1
#define GA_ALERT         2
#define GA_EVAC_INH_SIL  3
#define GA_EVAC_AUT_SIL  4
#define GA_EVAC          5

/* offset for function call */
#define O_ALARM_EVENT    0
#define O_TIMER_EVENT    1
#define O_PB_EVENT       2
#define O_DRIVER_EVENT   3

/* masks for ga table */
#define M_GA_ON          (0x01)
#define M_NEW_GA         (0x02)

/* posible ga output status command*/
#define GA_OUT_OFF       (0)
#define GA_OUT_ON        (1)
#define GA_OUT_ALERT     (2)

/* timer start request */
#define START_PRE_ALERT  0
#define START_ALERT      1
#define START_EVAC_INH   2
#define START_EVAC_AUTO  3
#define START_EVAC       4
#define START_NORMAL     5

/*****************************************************************************
*                     G L O B A L     V A R I A B L E S
*****************************************************************************/

/* none */

/*****************************************************************************
*                E X T E R N A L     D E F I N I T I O N S
*****************************************************************************/

extern Rom_03668 rom_03668;

/*****************************************************************************
*            M O D U L E     S T A T I C     V A R I A B L E S
*****************************************************************************/

/* none */


/*****************************************************************************

  Function Name: mod_03668

  Description: this function will handle the inputs  from the  mailboxes
      and  call  the right  routine according  to the current state.

  Input: p_cfg: a pointer to a Rom_03668 structure.

  Output: none.

  Calls: mbox_rd_rm_mv_next, err_hdl, timer_ev_hdl, ga_output_hdl,
         ga_pb_ev_hdl and alm_ev_hdl.

  Coded by: Charles Brunet
      date: May 17/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get ram pointer
  WHILE (there is letters in the PB and timer mailbox)
  : IF (it's a timer event)
  : : IF (it's the delay timer)
  : : : call timer event handler
  : : ELSEIF (it's the ga driver timer)
  : : : call ga output handler
  : : ENDIF
  : ELSEIF (it's a pb event)
  : : IF (the pb status is on)
  : : : call the ga push button event handler
  : : ENDIF
  : ELSE
  : : call error handler
  : ENDIF
  ENDWHILE

  WHILE (there is letters in the ga alarm mailbox)
  : set the evac request to FALSE
  : IF (it's a status event)
  : : IF (the input is not diabled for GA)
  : : : SWITCH (current status of input)
  : : : : CASE NORMAL
  : : : : CASE FAULT
  : : : : : clear the ga flag for this input device
  : : : : ENDCASE
  : : : :
  : : : : CASE CONFIRMED_ALARM
  : : : : CASE SHORT_ALARM
  : : : : : set the ga flag and the new alarm flag for this input device
  : : : : : IF (the input device is configured as immediate evacuation)
  : : : : : : set the evac request to TRUE
  : : : : ENDCASE
  : : : call the alarm event handler
  : ELSE
  : : call error handler
  : ENDIF
  ENDWHILE
  IF (new data was received)
  : call the alart event handler with the evac request flag
  ENDIF
  clear all new alarm flags

*****************************************************************************
*                                 C O D E
*****************************************************************************/

void mod_03668(p_cfg)
Rom_03668 *p_cfg; {

  Mbox_event mbox_ev;
  Timer_ev *p_timer_ev;
  Pb_ev *p_pb_ev;
  Status_ev *p_sts_ev;
  Ram_03668 *p_ram;
  INT16 timer_ev_hdl(), ga_output_hdl(), ga_pb_ev_hdl(), alm_ev_hdl();
  INT16 clear_new_alm(), update;
  INT8 evac_req, cfg;

  p_ram = p_cfg->p_ram;
  update = FALSE;
  while(mbox_rd_rm_mv_next(p_cfg->p_pb_t_mbox_cb, &mbox_ev) == MBOX_OK) {
    if (mbox_ev.type == TIMER_EVENT) {
      p_timer_ev = (Timer_ev *)&mbox_ev;
      if (p_timer_ev->timer_id == &p_ram->t_id_delay) {
        timer_ev_hdl(p_cfg);
      } else if (p_timer_ev->timer_id == &p_ram->t_id_ga_drv) {
        ga_output_hdl(p_cfg);
      }
    } else if (mbox_ev.type == PB_EVENT) {
      p_pb_ev = (Pb_ev *)&mbox_ev;
      if (p_pb_ev->pb_rec.ctl_rec.status == PB_ON) {
        ga_pb_ev_hdl(p_cfg, p_pb_ev->pb_rec.ctl_rec.ctl_id);
      }
    } else {
      err_hdl(0x3668, FERR_03668_00);
    }
  }

  while(mbox_rd_rm_mv_next(p_cfg->p_alm_mbox_cb, &mbox_ev) == MBOX_OK) {
    evac_req = FALSE;
    if (mbox_ev.type == STATUS_EVENT) {
      p_sts_ev = (Status_ev *)&mbox_ev;
      cfg = *(INT8 *)field_cfg_read(p_cfg->p_idv_cfg[p_sts_ev->idv_id.loop][p_sts_ev->idv_id.dev]);
      cfg &= M_IDV_GA_CFG;
      if (cfg != 0 && p_sts_ev->fh_display_sts == IDV_DISP_ALARM) {
        update = TRUE;
        switch(p_sts_ev->active_status) {
          case WARNING2:
          case WARNING1:
          case NORMAL:
          case FAULT:
            p_cfg->p_ga_tb[p_sts_ev->idv_id.loop][p_sts_ev->idv_id.dev] = GA_OFF;
          break;
          case ALM_CONFIRMED:
          case SHORT_ALM:
            p_cfg->p_ga_tb[p_sts_ev->idv_id.loop][p_sts_ev->idv_id.dev] = M_GA_ON+M_NEW_GA;
            evac_req = (cfg == IDV_GA_IMMEDIATE) ? (TRUE) : (FALSE);
          break;
        }
      }
    } else {
      err_hdl(0x3668, FERR_03668_01);
    }
  }
  if (update == TRUE) {
    alm_ev_hdl(p_cfg, evac_req);
  }
  clear_new_alm(p_cfg);
}


/*****************************************************************************

  Function Name:   alm_ev_hdl

  Description:  this  function will  handle the ga alarm  event when  in
      normal state.

  Input: p_cfg: a pointer to a Rom_03668.

  Output: none.

  Calls: scan_tb, do_timers, timer_clear and ddb_mgr.

  Coded by: Charles Brunet
      date: May 17/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get number of alarms
  find out if there's new alarms
  SWITCH (current state)
  : CASE (normal)
  : : IF (the alarm count is 1)
  : : : go for pre_alert state
  : : ELSEIF (the count is greater than 1)
  : : : go for evacuation inhibit silence state
  : : ENDIF
  : ENDCASE
  : CASE (pre ga alert)
  : : IF (there is new alarms and the alarm count > 1)
  : : : clear delay timer
  : : : go for evecuation inhibit state
  : : ENDIF
  : ENDCASE
  : CASE (alert)
  : : IF (there is new alarms and the alarm count > 1)
  : : : clear delay timer
  : : : clear ga driver timer
  : : : set silenced flag to FALSE
  : : : go for evecuation inhibit state
  : : : clear the silenced led
  : : ELSEIF (alarm count is zero)
  : : : state is normal state
  : : : set silenced flag to FALSE
  : : : turn off silenced led
  : : ENDIF
  : ENDCASE
  : CASE (evacuation auto silence)
  : CASE (evacuation inhibit silence)
  : : IF (there is new alarms)
  : : : clear delay timer
  : : : go for evecuation inhibit state
  : : ENDIF
  : ENDCASE
  : CASE (evacuation)
  : : IF (there is new alarms)
  : : : clear delay timer
  : : : set silenced flag to FALSE
  : : : go for evecuation inhibit state
  : : : clear the silenced led
  : : ELSEIF (alarm count is zero)
  : : : state is normal state
  : : : set silenced flag to FALSE
  : : : turn off silenced led
  : : ENDIF
  : ENDCASE
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 alm_ev_hdl(p_cfg, evac_req)
Rom_03668 *p_cfg;
INT8 evac_req; {

  INT16 count, scan_tb(), command, new_alm;
  Ram_03668 *p_ram;

  p_ram = p_cfg->p_ram;
  new_alm = scan_tb(p_cfg, &count);
  switch(p_ram->ga_fsm) {
    case NORMAL:
      if (count == 1 && evac_req == FALSE) {
        command = START_PRE_ALERT;
        do_timers(p_cfg, command);
      } else if (count > 1 || evac_req == TRUE) {
        command = START_EVAC_INH;
        do_timers(p_cfg, command);
      }
      break;
    case PRE_GA_ALERT:
      if ((new_alm == TRUE && count > 1) || evac_req == TRUE) {
        timer_clear(&p_ram->t_id_delay);
        command = START_EVAC_INH;
        p_ram->ga_silenced = FALSE;
        do_timers(p_cfg, command);
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      }
      break;
    case GA_ALERT:
      if ((new_alm == TRUE && count > 1) || evac_req == TRUE) {
        timer_clear(&p_ram->t_id_delay);
        timer_clear(&p_ram->t_id_ga_drv);
        command = START_EVAC_INH;
        p_ram->ga_silenced = FALSE;
        do_timers(p_cfg, command);
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      } else if (count == 0) {
        p_ram->ga_fsm = GA_NORMAL;
        p_ram->ga_silenced = FALSE;
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      }
      break;
    case GA_EVAC_INH_SIL:
    case GA_EVAC_AUT_SIL:
      if (new_alm == TRUE) {
        timer_clear(&p_ram->t_id_delay);
        command = START_EVAC_INH;
        p_ram->ga_silenced = FALSE;
        do_timers(p_cfg, command);
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      }
      break;
    case GA_EVAC:
      if (new_alm == TRUE) {
        timer_clear(&p_ram->t_id_delay);
        command = START_EVAC_INH;
        p_ram->ga_silenced = FALSE;
        do_timers(p_cfg, command);
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      } else if (count == 0) {
        p_ram->ga_fsm = GA_NORMAL;
        p_ram->ga_silenced = FALSE;
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      }
      break;
  }
}


/*****************************************************************************

  Function Name: timer_ev_hdl

  Description: this function will handle the pre ga alert timer event.

  Input: p_cfg: a pointer to a Rom_03668.

  Output: none.

  Calls: do_timers and ddb_mgr.

  Coded by: Charles Brunet
      date: May 17/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get number of alarms
  find out if there's new alarms
  SWITCH (current state)
  : CASE (pre ga alert)
  : : go for alert state
  : ENDCASE
  : CASE (ga alert)
  : : IF (alarm count is zero)
  : : : go for normal state
  : : ELSE
  : : : clear the ga driver timer
  : : : go for evacuation inhibit state
  : : ENDIF
  : ENDCASE
  : CASE (evacuation inhibit)
  : : go for evacuation auto silence state
  : ENDCASE
  : CASE (evacuation auto silence)
  : : IF (alarm count is zero)
  : : : clear the silenced led
  : : : go for normal state
  : : ELSE
  : : : go for evacuation state
  : : : light up silenced led
  : : ENDIF
  : ENDCASE
  : CASE (others)
  : : call error handler
  : ENDCASE
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 timer_ev_hdl(p_cfg)
Rom_03668 *p_cfg; {

  INT16 command, count, scan_tb();
  Ram_03668 *p_ram;

  p_ram = p_cfg->p_ram;
  scan_tb(p_cfg, &count);
  switch(p_ram->ga_fsm) {
    case PRE_GA_ALERT:
      command = START_ALERT;
      do_timers(p_cfg, command);
      break;
    case GA_ALERT:
      if (count == 0) {
        p_ram->ga_fsm = NORMAL;
        p_ram->ga_silenced = FALSE;
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
      } else {
        timer_clear(&p_cfg->p_ram->t_id_ga_drv);
        command = START_EVAC_INH;
        do_timers(p_cfg, command);
      }
      break;
    case GA_EVAC_INH_SIL:
      command = START_EVAC_AUTO;
      do_timers(p_cfg, command);
      break;
    case GA_EVAC_AUT_SIL:
      if (count == 0) {
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
        command = START_NORMAL;
        do_timers(p_cfg, command);
      } else {
        command = START_EVAC;
        p_ram->ga_silenced = TRUE;
        ddb_mgr(p_cfg->ga_sil_zn_id, STS_OFFNORMAL+HIPRI_DCD);
        do_timers(p_cfg, command);
      }
      break;
  }
}


/*****************************************************************************

  Function Name: ga_pb_ev_hdl

  Description: this function will handle the ga silence PB event.

  Input: p_cfg: a pointer to a Rom_03668.
         pb_id: the id of the push button

  Output: none.

  Calls: ga_output_if and ddb_mgr.

  Coded by: Charles Brunet
      date: May 17/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  SWITCH (push button id)
  : CASE (ga on push button)
  : : clear timer for ga output driver
  : : set silenced to off
  : : set ga output to on
  : : turn off silenced led
  : ENDCASE
  :
  : CASE (ga off push button)
  : : clear the ga driver timer
  : : SWITCH (current state)
  : : : CASE (normal)
  : : : : set silenced to FALSE
  : : : : turn ga output off
  : : : : turn silenced led off
  : : : ENDCASE
  : : :
  : : : CASE (ga alert)
  : : : : IF (silence for alert stage is enabled)
  : : : : : set silenced to TRUE
  : : : : : turn ga output off
  : : : : : turn silenced led on
  : : : : ENDIF
  : : : ENDCASE
  : : :
  : : : CASE (ga evac auto)
  : : : CASE (ga evac)
  : : : : IF (the alarm count is zero)
  : : : : : set silenced to FALSE
  : : : : : turn ga output off
  : : : : : turn silenced led off
  : : : : ELSE
  : : : : : set silenced to TRUE
  : : : : : turn ga output off
  : : : : : turn silenced led on
  : : : : ENDIF
  : : : ENDCASE
  : : ENDSWITCH
  : ENDCASE
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 ga_pb_ev_hdl(p_cfg, pb_id)
Rom_03668 *p_cfg;
PB_ID pb_id; {

  INT16 ga_output_if(), count, scan_tb();
  Ram_03668 *p_ram;

  p_ram = p_cfg->p_ram;

  scan_tb(p_cfg, &count);
  switch (pb_id) {
    case PB_GA_ON:
      timer_clear(&p_cfg->p_ram->t_id_ga_drv);
      p_ram->ga_silenced = FALSE;
      ga_output_if(p_cfg, GA_OUT_ON);
      ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
    break;
    case PB_GA_OFF:
      switch (p_ram->ga_fsm) {
        case GA_NORMAL:
          timer_clear(&p_cfg->p_ram->t_id_ga_drv);
          p_ram->ga_silenced = FALSE;
          ga_output_if(p_cfg, GA_OUT_OFF);
          ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
        break;
        case GA_ALERT:
          if(((*(INT8 *)field_cfg_read(p_cfg->p_fh_cfg))&M_ALERT_SILENCE)!=0){
            timer_clear(&p_cfg->p_ram->t_id_ga_drv);
            p_ram->ga_silenced = TRUE;
            ga_output_if(p_cfg, GA_OUT_OFF);
            ddb_mgr(p_cfg->ga_sil_zn_id, STS_OFFNORMAL+HIPRI_DCD);
          }
        break;
        case GA_EVAC_AUT_SIL:
        case GA_EVAC:
          timer_clear(&p_cfg->p_ram->t_id_ga_drv);
          if (count == 0) {
            p_ram->ga_silenced = FALSE;
            ga_output_if(p_cfg, GA_OUT_OFF);
            ddb_mgr(p_cfg->ga_sil_zn_id, STS_NORMAL+HIPRI_DCD);
          } else {
            p_ram->ga_silenced = TRUE;
            ga_output_if(p_cfg, GA_OUT_OFF);
            ddb_mgr(p_cfg->ga_sil_zn_id, STS_OFFNORMAL+HIPRI_DCD);
          }
        break;
      }
    break;
  }
}


/*****************************************************************************

  Function Name: ga_output_hdl

  Description: this routine will set the ga ouput status for alert stage.

  Input: p_cfg:  a pointer to a display configuration.

  Output: none.

  Calls: ga_output_if.

  Coded by: Charles Brunet
      date: May 16/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get ram pointer
  SWITCH (current state)
  : CASE (ga alert)
  : : IF (ga ouput is on)
  : : : IF (off timer value is not zero)
  : : : : start off timer
  : : : : set ga ouput status to off
  : : : ENDIF
  : : ELSE
  : : : IF (on timer value is not zero)
  : : : : start on timer
  : : : : set ga ouput status to on
  : : : ENDIF
  : : ENDIF
  : ENDCASE
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 ga_output_hdl(p_cfg)
Rom_03668 *p_cfg; {

  INT16 ga_output_if();
  INT32 mili_secs;

  if (p_cfg->p_ram->ga_current == ODV_CD_ON) {
    mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_off_val)) * TIMER_HALF_SEC_BY_BIT;
    if (mili_secs != 0) {
      timer_start(mili_secs, NULL, p_cfg->p_pb_t_mbox_cb, &p_cfg->p_ram->t_id_ga_drv);
      p_cfg->p_ram->ga_current = ODV_CD_OFF;
      ga_output_if(p_cfg, GA_OUT_OFF);
    }
  } else {
    mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_on_val)) * TIMER_HALF_SEC_BY_BIT;
    if (mili_secs != 0) {
      timer_start(mili_secs, NULL, p_cfg->p_pb_t_mbox_cb, &p_cfg->p_ram->t_id_ga_drv);
      p_cfg->p_ram->ga_current = ODV_CD_ON;
      ga_output_if(p_cfg, GA_OUT_ON);
    }
  }
}


/*****************************************************************************

  Function Name: do_timers

  Description:    this  function  will  start  the  timer  according  to
      configuration, set the current state accordingly and set the right
      signal on the ga output.

  Input: p_cfg: a pointer to a Rom_03668.
         command: the timer to start.

  Output: none.

  Calls: timer_start and ga_output_if.

  Coded by: Charles Brunet
      date: May 17/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get ram address
  SWITCH (current state)
  : CASE (normal)
  : : : next state is normal
  : : : set silenced flag to FALSE
  : : : set ga output to off
  : ENDCASE
  : CASE (pre ga alert)
  : : IF (alert timer value is not zero)
  : : : next state is ga alert
  : : : start alert timer
  : : : set ga output to off
  : : : exit switch
  : : ENDIF
  : CASE (alert state)
  : : IF (inhibit timer value is not zero and ga is not silenced)
  : : : next state is evac inhibit
  : : : start evac inhibit timer
  : : : set ga output to alert
  : : : exit switch
  : : ENDIF
  : CASE (ga evac inhibit)
  : : IF (auto timer value is not zero)
  : : : next state is evac auto
  : : : start evac auto timer
  : : : set ga output to on
  : : : exit switch
  : : ENDIF
  : CASE (ga evac auto)
  : : IF (auto timer value is not zero and ga is not silenced)
  : : : next state is evac auto silenced
  : : : start evac auto timer
  : : : set ga output to on
  : : : exit switch
  : : ENDIF
  : ENCASE
  : CASE (ga evac)
  : : IF (ga is silenced)
  : : : next state is evac
  : : : set ga output to off
  : : ELSE
  : : : next state is evac
  : : : set ga output to on
  : : ENDIF
  : ENCASE
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

do_timers (p_cfg, command)
Rom_03668 *p_cfg;
INT16 command; {

  Ram_03668 *p_ram;
  INT16 ga_output_if();
  INT32 mili_secs;

  p_ram = p_cfg->p_ram;
  switch(command) {
    case START_NORMAL:
      p_ram->ga_fsm = NORMAL;
      p_ram->ga_silenced = FALSE;
      ga_output_if(p_cfg, (INT8)GA_OUT_OFF);
      break;
    case START_PRE_ALERT:
      if ((*(INT8 *)field_cfg_read(p_cfg->p_fh_pa_val)) != 0) {
        p_ram->ga_fsm = PRE_GA_ALERT;
        mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_pa_val))*CONVERT_CFG_TIMER;
        timer_start(mili_secs, (INST_ID)NULL, p_cfg->p_pb_t_mbox_cb, &p_ram->t_id_delay);
        ga_output_if(p_cfg, (INT8)GA_OUT_OFF);
        break;
      }
    case START_ALERT:
      if ((*(INT8 *)field_cfg_read(p_cfg->p_fh_alert_val)) != 0 && p_ram->ga_silenced != TRUE) {
        p_ram->ga_fsm = GA_ALERT;
        mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_alert_val))*CONVERT_CFG_TIMER;
        timer_start(mili_secs, (INST_ID)NULL, p_cfg->p_pb_t_mbox_cb, &p_ram->t_id_delay);
        ga_output_if(p_cfg, (INT8)GA_OUT_ALERT);
        break;
      }
    case START_EVAC_INH:
      if ((*(INT8 *)field_cfg_read(p_cfg->p_fh_min_on_val)) != 0) {
        p_ram->ga_fsm = GA_EVAC_INH_SIL;
        mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_min_on_val))*CONVERT_CFG_TIMER;
        timer_start(mili_secs, (INST_ID)NULL, p_cfg->p_pb_t_mbox_cb, &p_ram->t_id_delay);
        ga_output_if(p_cfg, (INT8)GA_OUT_ON);
        break;
      }
    case START_EVAC_AUTO:
      if ((*(INT8 *)field_cfg_read(p_cfg->p_fh_auto_val)) != 0 && p_ram->ga_silenced != TRUE) {
        p_ram->ga_fsm = GA_EVAC_AUT_SIL;
        mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_auto_val))*TIMER_10S_BY_BIT;
        timer_start(mili_secs, (INST_ID)NULL, p_cfg->p_pb_t_mbox_cb, &p_ram->t_id_delay);
        ga_output_if(p_cfg, (INT8)GA_OUT_ON);
        break;
      }
    case START_EVAC:
      if (p_ram->ga_silenced == TRUE) {
        p_ram->ga_fsm = GA_EVAC;
        ga_output_if(p_cfg, (INT8)GA_OUT_OFF);
      } else {
        p_ram->ga_fsm = GA_EVAC;
        ga_output_if(p_cfg, (INT8)GA_OUT_ON);
      }
      break;
   }
}


/*****************************************************************************

  Function Name: scan_tb

  Description: this utility will scan the ga  table to count the  number
      of alarms.  The function will return TRUE if there  was new alarms
      compared to last run.

  Input: p_cfg: a pointer to a Rom_03668 structure.
         p_count: the contents will be the number af alarms.

  Output: TRUE: if there was new alarms registered in table.
          FALSE: if the was no new alarms registered in table.

  Calls: none.

  Coded by: Charles Brunet
      date: May 15/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  set return status to FALSE
  set count to zero
  WHILE (there is more idv's to scan)
  : IF (there is an alarm)
  : : increment count
  : : IF (it's a new alarm)
  : : : set return status to TRUE
  : : ENDIF
  : ENDIF
  ENDWHILE
  return (return status)

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 scan_tb(p_cfg, p_count)
Rom_03668 *p_cfg;
INT16 *p_count; {

  INT8 *const *p_tb;
  INT16 rtn_sts, c_loop, c_dev;

  rtn_sts = FALSE;
  if (p_count != NULL) {
    *p_count = 0;
  }
  p_tb = p_cfg->p_ga_tb;

  for (c_loop = 0 ; c_loop < NUM_LOOP ; c_loop++) {
    for (c_dev = 0; c_dev < NUM_LOOP_DEV ; c_dev++) {
      if (p_tb[c_loop][c_dev]) {
        if (p_count != NULL) {
          (*p_count)++;
        }
        if (p_tb[c_loop][c_dev] & M_NEW_GA) {
          rtn_sts = TRUE;
        }
      }
    }
  }
  return(rtn_sts);
}


/*****************************************************************************

  Function Name: ga_output_if

  Description:  this  function  will set the  ga ouput requested  status
      according to the current state of the module.

  Input: p_cfg:  a pointer to a display configuration.
         req_state: the requested ga status.

  Output: none.

  Calls: timer_start.

  Coded by: Charles Brunet
      date: May 16/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  save requested status in ram

  SWITCH (requeated ga output status)
  : CASE (OFF)
  : : set ga ouput to off
  : ENDCASE
  :
  : CASE (ON)
  : : set ga ouput  to on
  : ENDCASE
  :
  : CASE (ALERT)
  : : IF (on timer value is not zero)
  : : : set ga ouput status to on
  : : : start the ga on timer
  : : ENDIF
  : ENDCASE
  :
  ENDSWITCH

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 ga_output_if(p_cfg, req_state)
Rom_03668 *p_cfg;
INT8 req_state; {

  Ram_03668 *p_ram;
  INT32 mili_secs;

  p_ram = p_cfg->p_ram;
  p_ram->ga_out_req = req_state;
  p_cfg->p_ram->ga_current = req_state;
  switch (p_ram->ga_out_req) {
    case GA_OUT_OFF:
      drive_odv(p_cfg, ODV_CD_OFF);
      break;
    case GA_OUT_ON:
      drive_odv(p_cfg, ODV_CD_ON);
      break;
    case GA_OUT_ALERT:
      mili_secs = (*(INT8 *)field_cfg_read(p_cfg->p_fh_on_val)) * TIMER_HALF_SEC_BY_BIT;
      if (mili_secs != 0) {
        timer_start(mili_secs, NULL, p_cfg->p_pb_t_mbox_cb, &p_ram->t_id_ga_drv);
        drive_odv(p_cfg, ODV_CD_ON);
      }
      break;
  }
}


/*****************************************************************************

  Function Name: clear_new_alm

  Description: this routine will clear the new ga flag for  the whole GA
      table.

  Input: p_cfg:  a pointer to a display configuration.

  Output: none.

  Calls: none.

  Coded by: Charles Brunet
      date: Jun 15/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  get address of GA table
  WHILE (the whole table is not done)
  : clear the new ga flag fot this device
  ENDWHILE

*****************************************************************************
*                                 C O D E
*****************************************************************************/

INT16 clear_new_alm(p_cfg)
Rom_03668 *p_cfg; {

  INT8 *const *p_tb, c_loop, c_dev;

  p_tb = p_cfg->p_ga_tb;

  for (c_loop = 0 ; c_loop < NUM_LOOP ; c_loop++) {
    for (c_dev = 0; c_dev < NUM_LOOP_DEV ; c_dev++) {
      p_tb[c_loop][c_dev] &= ~M_NEW_GA;
    }
  }
}




/*****************************************************************************

  Function Name: drive_odv

  Description: this routine will drive all the outputs in the list that
       are configured as a ga output.

  Input: p_rom: a pointer to the rom configuration of the module.
         command: the state the output is commanded to.

  Output: none.

  Calls: so_control.

  Coded by: Charles Brunet
      date: Oct 06/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

WHILE(the end of the list is not reached)
: IF (output is configured as a ga output)
: : drive output
: ENDIF
ENDWHILE

IF (the extension card is present)
: WHILE(the end of the extension list is not reached)
: : IF (output is configured as a ga output)
: : : drive output
: : ENDIF
: ENDWHILE
ENDIF

*****************************************************************************
*                                 C O D E
*****************************************************************************/

drive_odv(p_rom, command)
Rom_03668 *p_rom;
INT8 command; {

  const Ga_odv *p_odv;

  p_odv = p_rom->board_odv;
  while(p_odv->p_fh_odv_cfg != NULL) {
    if (p_odv->disabled == 0) {
      if ((*(INT8 *)field_cfg_read(p_odv->p_fh_odv_cfg) & M_ODV_CFG) == M_ODV_GA) {
        so_control(&p_odv->odv_id, command);
      }
    }
    p_odv++;
  }
  if ((*(INT8 *)field_cfg_read(p_rom->p_fh_ext_cfg) & M_EXPANSION_CARD) == EXP_CARD_PRESENT) {
    p_odv = p_rom->ext_odv;
    while(p_odv->p_fh_odv_cfg != NULL) {
      if (p_odv->disabled == 0) {
        if ((*(INT8 *)field_cfg_read(p_odv->p_fh_odv_cfg) & M_ODV_CFG) == M_ODV_GA) {
          so_control(&p_odv->odv_id, command);
        }
      }
      p_odv++;
    }
  }
}


/*****************************************************************************

  Function Name: init_03668

  Description: this routine will initialise the neccessary items  needed
      for the module to run properly.

  Input: p_cfg:  a pointer to a display configuration.
         p_ga_pb_mbox: pointer to the pb pipe, if NULL: not initialised.
         p_ga_alm_mbox: pointer to the time pipe, if NULL: not initialised.

  Output: none.

  Calls: mbox_create.

  Coded by: Charles Brunet
      date: May 15/90

*****************************************************************************
*                         P S E U D O     C O D E
*****************************************************************************

  create push button pipe
  create push timer pipe
  init all timer id's to NULL

*****************************************************************************
*                                 C O D E
*****************************************************************************/

void init_03668(p_cfg, p_ga_pb_mbox, p_ga_alm_mbox)
Rom_03668 *p_cfg;
INT16 *p_ga_pb_mbox;
INT16 *p_ga_alm_mbox; {

  INT16 letter_size, mbox_size;

  if (p_ga_pb_mbox != NULL) {
    letter_size = sizeof(Mbox_event) / 2;
    mbox_size = SIZE_OF_PB_PIPE * sizeof(Mbox_event) / 2;
    if (mbox_create(letter_size, mbox_size, p_ga_pb_mbox, p_cfg->p_pb_t_mbox_cb) != MBOX_OK) {
      err_hdl(0x3668, FERR_03668_02);
    }
  }
  if (p_ga_alm_mbox != NULL) {
    letter_size = sizeof(Mbox_event) / 2;
    mbox_size = SIZE_OF_TIME_PIPE * sizeof(Mbox_event) / 2;
    if (mbox_create(letter_size, mbox_size, p_ga_alm_mbox, p_cfg->p_alm_mbox_cb) != MBOX_OK) {
      err_hdl(0x3668, FERR_03668_03);
    }
  }
  p_cfg->p_ram->ga_silenced = FALSE;
}
#endif
